#ifndef SRC_LTDSTR_H_
#define SRC_LTDSTR_H_

#include "src/lta.h"
#include "src/ltarena.h"
#include "src/ltbase.h"

#include <stdbool.h>

/**动态分配内存的字符串。

它可能拥有内存的所有权，也有可能内存属于某个Arena。*/
typedef struct {
    lta_Chars chars_;
    ltarena_Arena* arena_;
} ltdstr_String;

/** 为dstr设置Arena。

dstr需要没设置过arena，并且是空的。
*/
lt_ForceInline bool
ltdstr_SetArena(ltdstr_String* dstr, ltarena_Arena* arena) {
    if (dstr->arena_ != NULL || dstr->chars_.len != 0)
        return false;
    dstr->arena_ = arena;
    return true;
}

lt_ForceInline ltdstr_String
ltdstr_NewArenaString(ltarena_Arena* arena) {
    ltdstr_String s = {0};
    ltdstr_SetArena(&s, arena);
    return s;
}

lt_ForceInline void
ltdstr_DeInit(ltdstr_String* string) {
    if (string->arena_ == NULL) {
        lta_DeInit(string->chars_);
    } else {
        string->chars_ = (lta_Chars){0};
    }
}

lt_ForceInline void
ltdstr_Clear(ltdstr_String* string) {
    string->chars_.len = 0;
}

lt_ForceInline bool
ltdstr__EndsWithZero(ltdstr_String const* dstr) {
    return dstr->chars_.len > 0 && dstr->chars_.data[dstr->chars_.len - 1] == 0;
}

lt_ForceInline char const*
ltdstr_Get(ltdstr_String const* dstr) {
    if (dstr->chars_.len == 0)
        return "";
    return dstr->chars_.data;
}

lt_ForceInline lt_USize
ltdstr_Len(ltdstr_String const* dstr) {
    return dstr->chars_.len;
}

lt_ForceInline char*
ltdstr_GetMutable(ltdstr_String* dstr) {
    if (!ltdstr__EndsWithZero(dstr)) {
        lta_Append(dstr->chars_, 0);
    }
    return dstr->chars_.data;
}

lt_ForceInline void
ltdstr_Append(ltdstr_String* dstr, char const* text) {
    if (ltdstr__EndsWithZero(dstr)) {
        dstr->chars_.len -= 1;
    }

    if (dstr->arena_ == NULL) {
        for (; *text; ++text) {
            lta_Append(dstr->chars_, *text);
        }
        lta_Append(dstr->chars_, 0);
    } else {
        for (; *text; ++text) {
            ltaa_Append(dstr->arena_, dstr->chars_, *text);
        }
        ltaa_Append(dstr->arena_, dstr->chars_, 0);
    }
}

lt_ForceInline void
ltdstr_AppendChar(ltdstr_String* dstr, char c) {
    if (ltdstr__EndsWithZero(dstr)) {
        dstr->chars_.len -= 1;
    }

    if (dstr->arena_ == NULL) {
        lta_Append(dstr->chars_, c);
        lta_Append(dstr->chars_, 0);
    } else {
        ltaa_Append(dstr->arena_, dstr->chars_, c);
        ltaa_Append(dstr->arena_, dstr->chars_, 0);
    }
}

#endif // SRC_LTDSTR_H_
